package com.three.handler;

import com.three.api.event.HeartBeatEvent;
import com.three.common.message.base.*;
import com.three.common.message.base.gateway.GatewayKickPlayerMessage;
import com.three.common.message.base.gateway.GatewayPushMessage;
import com.three.common.push.GatewayPushResult;
import com.three.event.EventBus;
import com.three.netty.client.push.PushRequest;
import com.three.netty.client.push.PushRequestBus;
import com.three.netty.core.ack.AckTask;
import com.three.netty.core.ack.AckTaskQueue;
import com.three.netty.core.handler.annotation.PacketHandlerClass;
import com.three.netty.core.handler.annotation.PacketHandlerMethod;
import com.three.netty.core.push.PushCenter;
import com.three.common.receiver.ReceiverType;
import com.three.netty.core.router.RouterCenter;
import com.three.protocol.CommandEnum;
import com.three.service.BaseModuleService;
import com.three.utils.LogUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static com.three.common.ErrorCode.OFFLINE;
import static com.three.common.ErrorCode.PUSH_CLIENT_FAILURE;
import static com.three.common.ErrorCode.ROUTER_CHANGE;

/**
 * Created by mathua on 2017/5/30.
 */
@Service
@PacketHandlerClass
public class ChessBaseModuleHandler {

    @Autowired
    private BaseModuleService baseModuleService;

    @PacketHandlerMethod(msgId = CommandEnum.Command.HEARTBEAT, describe = "心跳包请求", receivers = {ReceiverType.CONNECTION_SERVER_RECEIVER})
    public void heartBeatHandler(HeartbeatReqMessage message) throws Exception {
        message.getConnection().send(HeartbeatRespMessage.from(message.getConnection()).getPacket());//ping -> pong
        EventBus.I.post(new HeartBeatEvent(message.getConnection().getSessionContext().getPlayerId()));
        LogUtils.HB.info("ping -> pong, {}", message.getConnection());
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.LOGIN, shouldVerifyIdentity = false, describe = "登录请求", receivers = {ReceiverType.WEB_SOCKET_SERVER_RECEIVER, ReceiverType.CONNECTION_SERVER_RECEIVER})
    public void loginHandler(LoginReqMessage message) throws Exception {
//        if (message.getConnection().getSessionContext().isSecurity()) {
//            baseModuleService.doSecurity(message);
//        } else {
            baseModuleService.doInsecurity(message);
//        }
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.LOGOUT, describe = "登出请求", receivers =  {ReceiverType.CONNECTION_SERVER_RECEIVER, ReceiverType.WEB_SOCKET_SERVER_RECEIVER})
    public void logoutHandler(LogoutMessage message) throws Exception {
        baseModuleService.logout(message);
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.FAST_CONNECT, describe = "快速连接请求", receivers = {ReceiverType.CONNECTION_SERVER_RECEIVER})
    public void fastConnectHandler(FastConnectReqMessage message) throws Exception {
        baseModuleService.fastConnect(message);
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.ERROR, describe = "错误消息通知", receivers = {ReceiverType.GATEWAY_CLIENT_RECEIVER})
    public void gatewayErrorHandler(ErrorMessage message) throws Exception {
        if (message.getCmd() == CommandEnum.Command.GATEWAY_PUSH.getNumber()) {
            PushRequest request = PushRequestBus.I.getAndRemove(message.getSessionId());
            if (request == null) {
                LogUtils.PUSH.warn("receive a gateway response, but request has timeout. message={}", message);
                return;
            }

            LogUtils.PUSH.warn("receive an error gateway response, message={}", message);
            if (message.getCode() == OFFLINE.errorCode) {//用户离线
                request.onOffline();
            } else if (message.getCode() == PUSH_CLIENT_FAILURE.errorCode) {//下发到客户端失败
                request.onFailure();
            } else if (message.getCode() == ROUTER_CHANGE.errorCode) {//用户路由信息更改
                request.onRedirect();
            }
        }
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.OK, describe = "ok消息通知", receivers = {ReceiverType.GATEWAY_CLIENT_RECEIVER})
    public void gatewayOkHandler(OkMessage message) throws Exception {
        if (message.getCmd() == CommandEnum.Command.GATEWAY_PUSH.getNumber()) {
            PushRequest request = PushRequestBus.I.getAndRemove(message.getSessionId());
            if (request == null) {
                LogUtils.PUSH.warn("receive a gateway response, but request has timeout. message={}", message);
                return;
            }
            request.onSuccess(GatewayPushResult.fromJson(message.getMsg()));//推送成功
        }
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.HTTP_PROXY, shouldVerifyIdentity = false, describe = "http请求", receivers = {ReceiverType.CONNECTION_SERVER_RECEIVER})
    public void httpProxyHandler(HttpRequestMessage message) throws Exception {
        baseModuleService.httpProxy(message);
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.GATEWAY_KICK, describe = "网关踢玩家下线", receivers = {ReceiverType.GATEWAY_CLIENT_RECEIVER, ReceiverType.GATEWAY_UDP_CONNECTOR_RECEIVER})
    public void gatewayKickPlayerHandler(GatewayKickPlayerMessage message) throws Exception {
        RouterCenter.I.getRouterChangeListener().onReceiveKickRemoteMsg(message);
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.PUSH, describe = "消息推送", receivers = {ReceiverType.WEB_SOCKET_SERVER_RECEIVER, ReceiverType.CONNECTION_SERVER_RECEIVER})
    public void clientPushHandler(PushMessage message) throws Exception {
        LogUtils.PUSH.info("receive client push message={}", message);

        if (message.autoAck()) {
            AckMessage.from(message).sendRaw();
            LogUtils.PUSH.info("send ack for push message={}", message);
        }
        //biz code write here
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.GATEWAY_PUSH, describe = "网关消息推送", receivers = {ReceiverType.GATEWAY_SERVER_RECEIVER, ReceiverType.GATEWAY_UDP_CONNECTOR_RECEIVER})
    public void gatewayPushHandler(GatewayPushMessage message) throws Exception {
        PushCenter.I.push(message);
    }

    @PacketHandlerMethod(msgId = CommandEnum.Command.ACK,describe = "确认消息", receivers = {ReceiverType.CONNECTION_SERVER_RECEIVER, ReceiverType.WEB_SOCKET_SERVER_RECEIVER})
    public void ackHandler(AckMessage message) throws Exception {
        AckTask task = AckTaskQueue.I.getAndRemove(message.getSessionId());
        if (task == null) {//ack 超时了
            LogUtils.PUSH.info("receive client ack, but task timeout message={}", message);
            return;
        }

        task.onResponse();//成功收到客户的ACK响应
    }

}
